﻿#region Apache 2.0 License header

//   Copyright 2012 Lesley van Zijl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License. 

#endregion

using System;
using System.Reflection;
using System.Reflection.Emit;
using FavourObjects;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Tests.Helpers;

namespace Tests
{
    [TestClass]
    public class FieldTests
    {
        #region Private field reference type

        [TestMethod]
        public void Private_Field_ReferenceType_Get()
        {
            var favourObject = FavourObject.Create<IPrivateFieldReferenceType>(new TargetTestClass());

            MethodInfo result = favourObject._fieldReferenceType;

            Assert.AreEqual("F", result.Name);
            Assert.AreEqual(typeof (Int32), result.ReturnType);
        }

        [TestMethod]
        public void Private_Field_ReferenceType_GetSet()
        {
            var favourObject = FavourObject.Create<IPrivateFieldReferenceType>(new TargetTestClass());

            favourObject._fieldReferenceType = new DynamicMethod("F", typeof (double), null);

            MethodInfo result = favourObject._fieldReferenceType;

            Assert.AreEqual("F", result.Name);
            Assert.AreEqual(typeof (double), result.ReturnType);

            favourObject._fieldReferenceType = new DynamicMethod("F", typeof (int), null);
        }

        public interface IPrivateFieldReferenceType
        {
            MethodInfo _fieldReferenceType { get; set; }
        }

        #endregion

        #region Private field value types

        [TestMethod]
        public void Private_Field_ValueType_Get()
        {
            var favourObject = FavourObject.Create<IPrivateFieldValueType>(new TargetTestClass());

            Assert.AreEqual(5, favourObject._fieldValueType);
        }

        [TestMethod]
        public void Private_Field_ValueType_GetSet()
        {
            var favourObject = FavourObject.Create<IPrivateFieldValueType>(new TargetTestClass());

            favourObject._fieldValueType = 89;

            Assert.AreEqual(89, favourObject._fieldValueType);

            favourObject._fieldValueType = 5;
        }

        public interface IPrivateFieldValueType
        {
            int _fieldValueType { get; set; }
        }

        #endregion

        #region Private static field reference type

        [TestMethod]
        public void PrivateStatic_Field_ReferenceType_Get()
        {
            var favourObject = FavourObject.Create<IPrivateStaticFieldReferenceType>(new TargetTestClass());

            MethodInfo testObject = favourObject._fieldStaticReferenceType;

            Assert.AreEqual(null, testObject);
        }

        [TestMethod]
        public void PrivateStatic_Field_ReferenceType_GetSet()
        {
            var favourObject = FavourObject.Create<IPrivateStaticFieldReferenceType>(new TargetTestClass());

            favourObject._fieldStaticReferenceType = new DynamicMethod("F", typeof (double), null);

            MethodInfo testObject = favourObject._fieldStaticReferenceType;

            Assert.AreEqual(testObject.Name, "F");
            Assert.AreEqual(typeof (double), testObject.ReturnType);

            favourObject._fieldStaticReferenceType = null;
        }

        public interface IPrivateStaticFieldReferenceType
        {
            MethodInfo _fieldStaticReferenceType { get; set; }
        }

        #endregion

        #region Private static field value type

        [TestMethod]
        public void PrivateStatic_Field_ValueType_Get()
        {
            var favourObject = FavourObject.Create<IPrivateStaticFieldValueType>(new TargetTestClass());

            Assert.AreEqual(90, favourObject._fieldStaticValueType);
        }

        [TestMethod]
        public void PrivateStatic_Field_ValueType_GetSet()
        {
            var favourObject = FavourObject.Create<IPrivateStaticFieldValueType>(new TargetTestClass());

            favourObject._fieldStaticValueType = 39;

            Assert.AreEqual(39, favourObject._fieldStaticValueType);

            favourObject._fieldStaticValueType = 90;
        }

        public interface IPrivateStaticFieldValueType
        {
            int _fieldStaticValueType { get; set; }
        }

        #endregion

        #region Public field tests

        [TestMethod]
        public void PublicStatic_ValueType_Field()
        {
            var favourObject = FavourObject.Create<IPublicFields>(new TargetTestClass());

            favourObject.PublicStaticValueTypeField = 39;

            Assert.AreEqual(39, favourObject.PublicStaticValueTypeField);

            favourObject.PublicStaticValueTypeField = default(int);
        }

        [TestMethod]
        public void Public_ValueType_Field()
        {
            var favourObject = FavourObject.Create<IPublicFields>(new TargetTestClass());

            favourObject.PublicValueTypeField = 39;

            Assert.AreEqual(39, favourObject.PublicValueTypeField);

            favourObject.PublicValueTypeField = default(int);
        }

        [TestMethod]
        public void PublicStatic_ReferenceType_Field()
        {
            var favourObject = FavourObject.Create<IPublicFields>(new TargetTestClass());

            favourObject.PublicStaticReferenceTypeField = new DynamicMethod("F", typeof (double), null);

            MethodInfo testObject = favourObject.PublicStaticReferenceTypeField;

            Assert.AreEqual(testObject.Name, "F");
            Assert.AreEqual(typeof (double), testObject.ReturnType);

            favourObject.PublicStaticReferenceTypeField = null;
        }

        [TestMethod]
        public void Public_ReferenceType_Field()
        {
            var favourObject = FavourObject.Create<IPublicFields>(new TargetTestClass());

            favourObject.PublicReferenceTypeField = new DynamicMethod("F", typeof (double), null);

            MethodInfo testObject = favourObject.PublicReferenceTypeField;

            Assert.AreEqual(testObject.Name, "F");
            Assert.AreEqual(typeof (double), testObject.ReturnType);

            favourObject.PublicReferenceTypeField = null;
        }

        public interface IPublicFields
        {
            int PublicStaticValueTypeField { get; set; }
            int PublicValueTypeField { get; set; }
            MethodInfo PublicStaticReferenceTypeField { get; set; }
            MethodInfo PublicReferenceTypeField { get; set; }
        }

        #endregion

        #region Protected field tests

        [TestMethod]
        public void ProtectedStatic_ValueType_Field()
        {
            var favourObject = FavourObject.Create<IProtectedFields>(new TargetTestClass());

            favourObject.ProtectedStaticValueTypeField = 39;

            Assert.AreEqual(39, favourObject.ProtectedStaticValueTypeField);

            favourObject.ProtectedStaticValueTypeField = default(int);
        }

        [TestMethod]
        public void Protected_ValueType_Field()
        {
            var favourObject = FavourObject.Create<IProtectedFields>(new TargetTestClass());

            favourObject.ProtectedValueTypeField = 39;

            Assert.AreEqual(39, favourObject.ProtectedValueTypeField);

            favourObject.ProtectedValueTypeField = default(int);
        }

        [TestMethod]
        public void ProtectedStatic_ReferenceType_Field()
        {
            var favourObject = FavourObject.Create<IProtectedFields>(new TargetTestClass());

            favourObject.ProtectedStaticReferenceTypeField = new DynamicMethod("F", typeof (double), null);

            MethodInfo testObject = favourObject.ProtectedStaticReferenceTypeField;

            Assert.AreEqual(testObject.Name, "F");
            Assert.AreEqual(typeof (double), testObject.ReturnType);

            favourObject.ProtectedStaticReferenceTypeField = null;
        }

        [TestMethod]
        public void Protected_ReferenceType_Field()
        {
            var favourObject = FavourObject.Create<IProtectedFields>(new TargetTestClass());

            favourObject.ProtectedReferenceTypeField = new DynamicMethod("F", typeof (double), null);

            MethodInfo testObject = favourObject.ProtectedReferenceTypeField;

            Assert.AreEqual(testObject.Name, "F");
            Assert.AreEqual(typeof (double), testObject.ReturnType);

            favourObject.ProtectedReferenceTypeField = null;
        }

        public interface IProtectedFields
        {
            int ProtectedStaticValueTypeField { get; set; }
            int ProtectedValueTypeField { get; set; }
            MethodInfo ProtectedStaticReferenceTypeField { get; set; }
            MethodInfo ProtectedReferenceTypeField { get; set; }
        }

        #endregion

        #region Internal field tests

        [TestMethod]
        public void InternalStatic_ValueType_Field()
        {
            var favourObject = FavourObject.Create<IInternalFields>(new TargetTestClass());

            favourObject.InternalStaticValueTypeField = 39;

            Assert.AreEqual(39, favourObject.InternalStaticValueTypeField);

            favourObject.InternalStaticValueTypeField = default(int);
        }

        [TestMethod]
        public void Internal_ValueType_Field()
        {
            var favourObject = FavourObject.Create<IInternalFields>(new TargetTestClass());

            favourObject.InternalValueTypeField = 39;

            Assert.AreEqual(39, favourObject.InternalValueTypeField);

            favourObject.InternalValueTypeField = default(int);
        }

        [TestMethod]
        public void InternalStatic_ReferenceType_Field()
        {
            var favourObject = FavourObject.Create<IInternalFields>(new TargetTestClass());

            favourObject.InternalStaticReferenceTypeField = new DynamicMethod("F", typeof (double), null);

            MethodInfo testObject = favourObject.InternalStaticReferenceTypeField;

            Assert.AreEqual(testObject.Name, "F");
            Assert.AreEqual(typeof (double), testObject.ReturnType);

            favourObject.InternalStaticReferenceTypeField = null;
        }

        [TestMethod]
        public void Internal_ReferenceType_Field()
        {
            var favourObject = FavourObject.Create<IInternalFields>(new TargetTestClass());

            favourObject.InternalReferenceTypeField = new DynamicMethod("F", typeof (double), null);

            MethodInfo testObject = favourObject.InternalReferenceTypeField;

            Assert.AreEqual(testObject.Name, "F");
            Assert.AreEqual(typeof (double), testObject.ReturnType);

            favourObject.InternalReferenceTypeField = null;
        }

        public interface IInternalFields
        {
            int InternalStaticValueTypeField { get; set; }
            int InternalValueTypeField { get; set; }
            MethodInfo InternalStaticReferenceTypeField { get; set; }
            MethodInfo InternalReferenceTypeField { get; set; }
        }

        #endregion
    }
}